#include "mainbox.h"
#include "ui_mainbox.h"

MainBox::MainBox(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::MainBox)
{
    ui->setupUi(this);
    ui_init();
}

MainBox::~MainBox()
{
    delete ui;
}

void MainBox::ui_init()
{
    m_gridlayout->addWidget(m_logbrowser,0,0,4,4);
    m_gridlayout->addWidget(m_testbtn,4,0,1,4);
    m_gridlayout->addWidget(m_inputLogMsg,5,0,1,2);
    m_gridlayout->addWidget(m_writeLog,5,2,1,2);
    //this->setFixedSize(500,300);
    connect(m_logbrowser,&QTextBrowser::textChanged,[=](){
        m_logbrowser->moveCursor(QTextCursor::End);
    });

    connect(m_testbtn,&QPushButton::clicked,this,&MainBox::debug);

    connect(m_writeLog,&QPushButton::clicked,[=](){
        this->Py_Tester();
    });
}

void MainBox::showlog(QString text)
{
    QString log_t = QDateTime::currentDateTime().toString("yyyy-dd-MM hh:mm:ss");
    QFont ft;
    ft.setBold(true);
    ft.setPointSize(10);
    m_logbrowser->setFont(ft);
    //文本浏览器颜色字体设置
    if(b_color)
    {
        m_logbrowser->append("<font color=\"#00FF00\">" + log_t +" "+ text + "</font>");
        b_color = false;
    }
    else {
        m_logbrowser->append("<font color=\"#FF0000\">" + log_t +" "+ text + "</font>");
        b_color = true;
    }
}

void MainBox::py_init()
{
    //初始化环境
    Py_Initialize();
    if(!Py_IsInitialized())
    {
        qDebug() << "init ERROR";
        PyErr_Print();
    }
    //配置添加当前目录搜索模块路径
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append('../PyScript')");
    //加载模块文件,与程序同级目录下的hello.py文件
    PyObject *pModule = PyImport_ImportModule("Tester");
    if(!pModule)
    {
        PyErr_Print();
        qDebug() << "module import Error";
    }
    else {
        //加载模块内部方法
        PyObject *pFuncHello = PyObject_GetAttrString(pModule,"hello_say");
        if(!pFuncHello){
            PyErr_Print();
            qDebug() << "func error";
        }
        else {
            //运行模块方法
            PyObject_CallFunction(pFuncHello,NULL);
        }
        //设置函数字符串参数
        PyObject * arg = PyUnicode_FromString("are you ok");
        PyObject * args = PyTuple_New(1);
        PyTuple_SetItem(args,0,arg);
        //调用方法
        PyObject *pFuncMsg = PyObject_GetAttrString(pModule,"msg");
        //传递参数
        PyObject *result = PyObject_CallObject(pFuncMsg,args);
        if(!result){
            PyErr_Print();
            // Alternatively, fetch and handle the error manually
            PyObject *ptype, *pvalue, *ptraceback;
            PyErr_Fetch(&ptype, &pvalue, &ptraceback);
            PyErr_NormalizeException(&ptype, &pvalue, &ptraceback);

            // Print error type
            if (ptype != nullptr) {
                PyObject* str_exc_type = PyObject_Repr(ptype);
                const char* err_type = PyUnicode_AsUTF8(str_exc_type);
                qDebug() << "Error type: " << err_type ;
                Py_XDECREF(str_exc_type);
            }

            // Print error value
            if (pvalue != nullptr) {
                PyObject* str_exc_value = PyObject_Repr(pvalue);
                const char* err_value = PyUnicode_AsUTF8(str_exc_value);
                qDebug() << "Error value: " << err_value;
                Py_XDECREF(str_exc_value);
            }

            // Print traceback
            if (ptraceback != nullptr) {
                PyObject* traceback_module = PyImport_ImportModule("traceback");
                PyObject* format_tb_func = PyObject_GetAttrString(traceback_module, "format_exception");
                PyObject* traceback_list = PyObject_CallFunctionObjArgs(format_tb_func, ptype, pvalue, ptraceback, nullptr);
                PyObject* traceback_str = PyUnicode_Join(PyUnicode_FromString(""), traceback_list);
                const char* tb = PyUnicode_AsUTF8(traceback_str);
                qDebug() << "Traceback: " << tb;

                Py_XDECREF(traceback_module);
                Py_XDECREF(format_tb_func);
                Py_XDECREF(traceback_list);
                Py_XDECREF(traceback_str);
            }

            // Clear error indicator
            PyErr_Clear();
        }
        else {
            PyObject *repr = PyObject_Repr(result);
            PyObject *str = PyUnicode_AsEncodedString(repr,"utf-8","strict");
            char *ret = PyBytes_AsString(str);
            this->showlog(QString(ret).remove("'"));
        }

        //多参数传递
        PyObject *arg1 = PyUnicode_FromString("TM1234566");
        PyObject *arg2 = PyUnicode_FromString("VTE");
        PyObject *arg3 = PyUnicode_FromString("123");
        PyObject *c_args = PyTuple_New(3);
        PyTuple_SetItem(c_args,0,arg1);
        PyTuple_SetItem(c_args,1,arg2);
        PyTuple_SetItem(c_args,2,arg3);
        //调用方法
        PyObject *pFuncCmd = PyObject_GetAttrString(pModule,"command");
        //传递参数
        PyObject *_ret = PyObject_CallObject(pFuncCmd,c_args);
        if(!_ret)
        {
            PyErr_Print();
            qDebug() << "command error";
        }
        else {
            PyObject *repr = PyObject_Repr(_ret);
            PyObject *str = PyUnicode_AsEncodedString(repr,"utf-8","strict");
            char *ret = PyBytes_AsString(str);
            this->showlog(QString(ret).remove("'"));
        }
    }
    //退出
    Py_Finalize();
}

void MainBox::Py_Tester()
{
    //init
    Py_Initialize();

    if(!Py_IsInitialized())
    {
        this->showlog("Init Python Script Error!!!");
        PyErr_Print();
    }
    else {
        //配置添加当前目录搜索模块路径
        PyRun_SimpleString("import sys");
        PyRun_SimpleString("sys.path.append('../PyScript')");

        //程序名
        QString product = QString::fromWCharArray(Py_GetProgramName());
        this->showlog(product);
        //执行路径
        product = QString::fromWCharArray(Py_GetPrefix());
        this->showlog(product);
        //执行路径
        product = QString::fromWCharArray(Py_GetExecPrefix());
        this->showlog(product);
        //可执行程序完整路径
        product = QString::fromWCharArray(Py_GetProgramFullPath());
        this->showlog(product);
        //模块搜索路径
        product = QString::fromWCharArray(Py_GetPath());
        this->showlog(product);
        //返回解释器版本
        product = QString(Py_GetVersion());
        this->showlog(product);
        //返回平台标识符
        product = QString(Py_GetPlatform());
        this->showlog(product);
        //返回官方版本字符串
        product = QString(Py_GetCopyright());
        this->showlog(product);
        //返回构建当前Python版本编译器的指示
        product = QString(Py_GetCompiler());
        this->showlog(product);
        //返回当前解释器实例序列号和构建日期
        product = QString(Py_GetBuildInfo());
        this->showlog(product);

        PyObject *pScriptPyFile = PyImport_ImportModule("UserModule");
        if(!pScriptPyFile){
            PyErr_Print();
            this->showlog("Module file Error");
        }
        else {
            this->showlog("Module Loading OK");
            //调用Python脚本的文件存储方法
            PyObject *pFunc = PyObject_GetAttrString(pScriptPyFile,"log_save");
            if(pFunc){
                this->showlog("找到 log_save 方法");
                QString log = m_logbrowser->toPlainText(); //m_inputLogMsg->text();
                if(log.length() <= 0){
                    log = "Are You OK";
                }
                //传递参数QString对象必须转换data，不然中文乱码
                PyObject *arg = PyUnicode_FromString(log.toUtf8().data());
                PyObject *args = PyTuple_New(1);
                PyTuple_SetItem(args,0,arg);
                //执行方法与传递参数
                PyObject *ret = PyObject_CallObject(pFunc,args);
                if(ret)
                {
                    this->showlog("log_save 执行完成");
                }
                else{
                    this->showlog("log_save 执行错误");
                }
            }
            //获取Python脚本方法中的获取无参文本函数
            PyObject *pFuncGetString = PyObject_GetAttrString(pScriptPyFile,"ret_msg");
            if(pFuncGetString)
            {
                this->showlog("ret_msg 方法寻找成功");
                PyObject *ret = PyObject_CallObject(pFuncGetString,NULL);
                if(ret){
                    this->showlog("ret_msg 方法调用成功");
                    //获取方法执行结果
                    QString _ret =QString(PyUnicode_AsUTF8(ret));
                    this->showlog(_ret);
                }
                else{
                    this->showlog("ret_msg 方法调用失败");
                }
            }
            //获取Python脚本方法中的获取有参文本函数
            PyObject *pFuncGetStringMsg = PyObject_GetAttrString(pScriptPyFile,"ret_str");
            if(pFuncGetStringMsg)
            {
                this->showlog("ret_str 方法寻找成功");
                PyObject *arg1 = PyUnicode_FromString("我是第一个参数");
                PyObject *arg2 = PyUnicode_FromString("我是第二个参数");
                PyObject *args = PyTuple_New(2);
                PyTuple_SetItem(args,0,arg1);
                PyTuple_SetItem(args,1,arg2);
                //调用方法，执行传参
                PyObject *ret = PyObject_CallObject(pFuncGetStringMsg,args);
                if(ret){
                    this->showlog("ret_str 方法调用成功");
                    //获取方法执行结果
                    QString _ret =QString(PyUnicode_AsUTF8(ret));
                    this->showlog(_ret);
                }
                else{
                    this->showlog("ret_str 方法调用失败");
                }
            }

            PyObject *pFuncCmd = PyObject_GetAttrString(pScriptPyFile,"command");
            if(pFuncCmd)
            {
                this->showlog("command 方法寻找成功");
                PyObject *arg1 = PyUnicode_FromString("First Cmd");
                PyObject *arg2 = PyUnicode_FromString("Two Cmd");
                PyObject *arg3 = PyUnicode_FromString("Three Cmd");
                PyObject *args = PyTuple_New(3);
                PyTuple_SetItem(args,0,arg1);
                PyTuple_SetItem(args,1,arg2);
                PyTuple_SetItem(args,2,arg3);
                //调用方法，执行传参
                PyObject *ret = PyObject_CallObject(pFuncCmd,args);
                if(ret){
                    this->showlog("command 方法调用成功");
                    //获取方法执行结果
                    QString _ret =QString(PyUnicode_AsUTF8(ret));
                    this->showlog(_ret);
                }
                else{
                    this->showlog("command 方法调用失败");
                }
            }
            //获取函数bool值结果
            PyObject *pFuncBool = PyObject_GetAttrString(pScriptPyFile,"ret_bool");
            if(pFuncBool)
            {
                this->showlog("ret_bool 方法寻找成功");
                PyObject *args = PyTuple_New(1);
                args = Py_BuildValue("(i)",40);
                //调用方法，执行传参
                PyObject *ret = PyObject_CallObject(pFuncBool,args);
                if(ret){
                    this->showlog("ret_bool 方法调用成功");
                    //获取方法执行结果
                    QString _ret = QString("%1").arg(PyObject_IsTrue(ret));
                    this->showlog(_ret);
                }
                else{
                    this->showlog("ret_bool 方法调用失败");
                }
            }
            //获取函数int类型结果
            PyObject *pFuncInt = PyObject_GetAttrString(pScriptPyFile,"ret_int");
            if(pFuncInt)
            {
                this->showlog("ret_int 方法寻找成功");
                PyObject *args = PyTuple_New(2);
                args = Py_BuildValue("(i,i)",60,5);
                //调用方法，执行传参
                PyObject *ret = PyObject_CallObject(pFuncInt,args);
                if(ret){
                    this->showlog("ret_int 方法调用成功");
                    //获取方法执行结果
                    int _rets = PyLong_AsLong(ret);
                    QString _ret =QString("%1").arg(_rets);
                    this->showlog(_ret);
                }
                else{
                    this->showlog("ret_int 方法调用失败");
                }
            }
            //获取数组结果
            PyObject *pFuncList = PyObject_GetAttrString(pScriptPyFile,"ret_list");
            if(pFuncList)
            {
                this->showlog("ret_list 方法寻找成功");
                PyObject *args = PyTuple_New(1);
                args = Py_BuildValue("(s)","hello word!!!");
                //调用方法，执行传参
                PyObject *ret = PyObject_CallObject(pFuncList,args);
                if(ret){
                    this->showlog("ret_list 方法调用成功");
                    QList<QString> tmp;
                    //获取方法执行结果
                    Py_ssize_t size = PyList_GET_SIZE(ret);
                    for (Py_ssize_t pos=0;pos<size;pos++) {
                        PyObject *pVar = PyList_GetItem(ret,pos);
                        QString _ret =QString(PyUnicode_AsUTF8(pVar));
                        this->showlog(_ret);
                        tmp.append(_ret);
                        /*  减少对象 o 的引用计数。
                         *  如果引用计数达到零，则会发起调用对象类型的撤销分配函数 (该函数必须不为 NULL)。
                         *  此函数通常被用于在退出作用域之前删除一个 strong reference。
                         */
                        Py_DecRef(pVar);
                    }
                    qDebug() << tmp;
                }
                else{
                    this->showlog("ret_list 方法调用失败");
                }
            }
            //获取字典内容
            PyObject *pFuncDict = PyObject_GetAttrString(pScriptPyFile,"ret_dict");
            if(pFuncDict)
            {
                this->showlog("ret_dict 方法寻找成功");
                //调用方法
                PyObject *ret = PyObject_CallObject(pFuncDict,NULL);
                if(ret){
                    this->showlog("ret_dict 方法调用成功");
                    //获取方法执行结果
                    PyObject *pKey,*pValue;
                    Py_ssize_t pos=0;
                    while (PyDict_Next(ret,&pos,&pKey,&pValue)) {
                        // 打印 key 和 value
                        PyObject* pKeyStr = PyObject_Str(pKey);
                        PyObject* pValueStr = PyObject_Str(pValue);
                        QString msg = QString("Key=%1,Value=%2").arg(PyUnicode_AsUTF8(pKeyStr)).arg(PyUnicode_AsUTF8(pValueStr));
                        this->showlog(msg);
                        Py_DecRef(pKeyStr);
                        Py_DecRef(pValueStr);
                    }
                }
                else{
                    this->showlog("ret_dict 方法调用失败");
                }
            }
        }
    }
    //release
    Py_Finalize();
}

void MainBox::debug()
{
    this->Py_Tester();
}

